/*
    URL编码解码实现部分 
*/
#include "urlEncoderAndDecoder.h"
#include <exception>
#include <assert.h>

unsigned char urlEncoderAndDecoder::charToHex(unsigned char x) {
    return x > 9 ? x + 55 : x + 48;
}

unsigned char urlEncoderAndDecoder::hexToChar(unsigned char x) {
    unsigned char y;
    if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;
    else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;
    else if (x >= '0' && x <= '9') y = x - '0';
    else
        assert(0);
    return y;
}

std::string urlEncoderAndDecoder::encoder(const std::string& url)noexcept(false) {
    try{
        std::string strTemp;
        size_t length = url.length();
        for (size_t i = 0; i < length; i++) {
            if (isalnum((unsigned char) url[i]) ||
                (url[i] == '-') ||
                (url[i] == '_') ||
                (url[i] == '.') ||
                (url[i] == '~'))
                strTemp.push_back(url[i]);
            else if (url[i] == ' ')
                strTemp.push_back('+');
            else {
                strTemp.push_back('%');
                strTemp.push_back(this->charToHex((unsigned char) url[i] >> 4));
                strTemp.push_back(this->charToHex((unsigned char) url[i] % 16));
            }
        }
        return strTemp;
    } catch(std::exception& e) {
        logger->error("错误：{}({})", __FILE__, __LINE__);
        throw e;
    }
}

std::string urlEncoderAndDecoder::decoder(const std::string& url)noexcept(false) {
    try{
        std::string strTemp = "";
        size_t length = url.length();
        for (size_t i = 0; i < length; i++) {
            if (url[i] == '+') strTemp.push_back(' ');
            else if (url[i] == '%') {
                assert(i + 2 < length);
                unsigned char high = this->hexToChar((unsigned char) url[++i]);
                unsigned char low = this->hexToChar((unsigned char) url[++i]);
                strTemp.push_back(high * 16 + low);
            } else strTemp.push_back(url[i]);
        }
        return strTemp;
    } catch(std::exception &e) {
        logger->error("错误：{}({})", __FILE__, __LINE__);
        throw e;
    }
}